package version2;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;

public class RandomWalk {

	private HashMap<Integer, HashMap<Integer, Integer>> npList;
	private HashMap<Integer, HashMap<Integer, Integer>> contextList;
	private HashMap<Integer, ArrayList<Integer>> probability;
	private HashMap<Integer, Integer> reachedNum;
	private HashMap<Integer, Double> prob;
	public static int numtimes = 10000;

	public RandomWalk() {
		npList = new HashMap<Integer, HashMap<Integer, Integer>>();
		prob = new HashMap<Integer, Double>();
		contextList = new HashMap<Integer, HashMap<Integer, Integer>>();
		probability = new HashMap<Integer, ArrayList<Integer>>();
		reachedNum = new HashMap<Integer, Integer>();
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		RandomWalk rw = new RandomWalk();
		rw.readNP("../matrix1.txt");
System.out.println("load file 1 finished!");		
rw.readContext("../matrix2.txt");
System.out.println("load file 2 finished!");
		rw.readProbability("../context.txt");
		//int numtimes = 10000;
		System.out.println("load file finished!");
		rw.walk(6, numtimes);
	

	}

	public void walk(int noun, int numtimes) {
		for (int i = 0; i < numtimes; i++) {
			//System.out.println(i);
			if(i == 100){
				//System.out.println("====================================100================================");
//				outputNP();
				Set<Integer> keys = reachedNum.keySet();
				for(int a: keys){
					System.out.println(i+"\t"+a+"\t" + reachedNum.get(a));
				}
				
				
			}
			else if(i ==  1000){
//				System.out.println("====================================1000================================");
//				outputNP();
				Set<Integer> keys = reachedNum.keySet();
				for(int a: keys){
					System.out.println(i+"\t"+a+"\t" + reachedNum.get(a));
				}
				
			}
			else if(i == 9999){
//				System.out.println("====================================9999================================");
//				outputNP();
				Set<Integer> keys = reachedNum.keySet();
				for(int a: keys){
					System.out.println(i+"\t"+a+"\t" + reachedNum.get(a));
				}
				
			}
			int context = chooseContext(1);
			int np = chooseNP(context);
			saveNPNumber(np);
			updateWeights();
		}
	}

	public void outputNP() {
		Set<Integer> keys = reachedNum.keySet();
		ArrayList<Integer> keyarray = new ArrayList<Integer>(keys);
		
		Collections.sort(keyarray, new RWComparator(reachedNum));
		for(int i = 0; i < 1000; i++){
			System.out.println(keyarray.get(i)+ ": " + reachedNum.get(keyarray.get(i)));
		}
	}

	public void updateWeights() {

		// set all the context's prob to 0;
		for (Iterator<Entry<Integer, Double>> it = prob.entrySet().iterator(); it.hasNext();) {
			Entry<Integer, Double> e = it.next();
			// int c1 = (Integer) e.getKey();
			e.setValue(0.);
		}
		// update
		for (Iterator<Entry<Integer, Integer>> iter = reachedNum.entrySet().iterator(); iter.hasNext();) {

			Entry<Integer, Integer> entry = iter.next();
			//int np =  entry.getKey();
			int reachedTimes = entry.getValue();
			//HashMap<Integer, Integer> contexts = contextList.get(np);

			for (Iterator<Entry<Integer, Double>> it = prob.entrySet().iterator(); it.hasNext();) {

				Entry<Integer, Double> e =  it.next();
				//int c = e.getKey();
				double number =  e.getValue();

				double newNumber = number + reachedTimes;
				e.setValue(newNumber);
			}
		}
		for (Iterator<Entry<Integer, Double>> it = prob.entrySet().iterator(); it.hasNext();) {

			Entry<Integer, Double> e = it.next();
			// int c = (Integer) e.getKey();
			double number1 =  e.getValue();
			double newNumber = number1 / numtimes;
			e.setValue(newNumber);
		}
	}

	public void saveNPNumber(int np) {
		if (reachedNum.containsKey(np)) {
			reachedNum.put(np, reachedNum.get(np) + 1);

		} else {
			reachedNum.put(np, 1);
		}
		//System.out.println(reachedNum);
	}

	public int chooseNP(int context) {
		HashMap<Integer, Integer> nps = npList.get(context);

		Set<Integer> npss = nps.keySet();
		ArrayList<Integer> nparray = new ArrayList<Integer>(npss);
		Random r = new Random();
		int rn = r.nextInt(nparray.size());

		return nparray.get(rn);

	}

	public int chooseContext(int np) {
		ArrayList<Integer> randomProb = probability.get(np);
		int size = randomProb.size();
		Random r = new Random();
		int randomNum = r.nextInt(size);
		return randomProb.get(randomNum);

	}

	public void readProbability(String filename) {

		try {
			// HashMap<Integer, Double> prob = new HashMap<Integer, Double>();
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String line;

			while ((line = br.readLine()) != null) {
				String[] str = line.split("\\s+");
				int context = Integer.parseInt(str[0]);
				double p = Double.parseDouble(str[1]);

				//
				// for(int i = 0; i < p * 100; i++){
				// probability.add(context);
				// }

				prob.put(context, p);

			}

			// Set<Entry<Integer, HashMap<Integer, Integer>>> entries =
			// contextList.entrySet();
			System.out.println("context load ok");
			for (Iterator<Entry<Integer, HashMap<Integer, Integer>>> iter = contextList
					.entrySet().iterator(); iter.hasNext();) {

				Entry<Integer, HashMap<Integer, Integer>> entry = iter.next();
				int np = entry.getKey();
				HashMap<Integer, Integer> contexts = entry.getValue();
				ArrayList<Integer> randomProb = new ArrayList<Integer>();

				for (Iterator<Entry<Integer, Integer>> it = contexts.entrySet()
						.iterator(); it.hasNext();) {
					Entry<Integer, Integer> e = it.next();
					int c = e.getKey();
					Double p = prob.get(c);

					for (int i = 0; i < p * 100; i++) {
						randomProb.add(c);
					}

				}
				probability.put(np, randomProb);
			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// System.out.println(probability);
	}

	public void readContext(String filename) {

		try {
			BufferedReader br = new BufferedReader(new FileReader(filename));

			int npNum = 0;
			HashMap<Integer, Integer> context = null;
			String line;

			while ((line = br.readLine()) != null) {
				String[] str = line.split("\\s+");
				int npNumber = Integer.parseInt(str[0]);

				if (npNumber != npNum) {
					contextList.put(npNum, context);
					context = new HashMap<Integer, Integer>();
					npNum = npNumber;
				}

				context.put(Integer.parseInt(str[1]), Integer.parseInt(str[2]));

			}
			br.close();
			contextList.remove(0);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// System.out.println(contextList);

	}

	public void readNP(String filename) {

		try {
			BufferedReader br = new BufferedReader(new FileReader(filename));
			String line;
			int contextNum = 0;
			HashMap<Integer, Integer> np = null;
			while ((line = br.readLine()) != null) {

				String[] str = line.split("\\s+");

				// System.out.println(str[0]);
				int c = Integer.parseInt(str[1]);
				// System.out.println(c);
				if (c != contextNum) {
					npList.put(contextNum, np);
					np = new HashMap<Integer, Integer>();
					contextNum = c;
				}

				np.put(Integer.parseInt(str[0]), Integer.parseInt(str[2]));

			}
			br.close();
			npList.remove(0);

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// System.out.println(npList);
	}

}
